/*
 * Copyright (C) 2016 Lokiy(liulongke@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  　　　　http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.lokiy.core.adapter

import android.graphics.*
import android.util.TypedValue
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.lokiy.core.R

interface IEmptyItemDecoration {

    /**
     * Called by RecyclerView when it starts observing this Adapter.
     * <p>
     * Keep in mind that same adapter may be observed by multiple RecyclerViews.
     *
     * @param recyclerView The RecyclerView instance which started observing this adapter.
     * @see #onDetachedFromRecyclerView(RecyclerView)
     */
    fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        synchronized(this) {
            if (isShowEmptyHeaderOnEmptyData()) {
                val observer: RecyclerView.AdapterDataObserver = object : RecyclerView.AdapterDataObserver() {
                    override fun onChanged() {
                        addOrRemoveEmptyHeaderDecor(recyclerView)
                    }

                    override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                        addOrRemoveEmptyHeaderDecor(recyclerView)
                    }

                    override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
                        addOrRemoveEmptyHeaderDecor(recyclerView)
                    }

                    override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
//                addEmptyHeaderDecor(recyclerView)
                    }
                }
                registerAdapterDataObserver(observer)
                recyclerView.setTag(R.id.empty_item_observer, observer)
                recyclerView.setTag(R.id.empty_item_decoration, EmptyHeaderDecoration(recyclerView, this))
            }
        }
    }

    /**
     * Called by RecyclerView when it stops observing this Adapter.
     *
     * @param recyclerView The RecyclerView instance which stopped observing this adapter.
     * @see .onAttachedToRecyclerView
     */
    fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        synchronized(this) {
            if (isShowEmptyHeaderOnEmptyData()) {
                val observer: RecyclerView.AdapterDataObserver = recyclerView.getTag(R.id.empty_item_observer) as RecyclerView.AdapterDataObserver
                unregisterAdapterDataObserver(observer)
                recyclerView.setTag(R.id.empty_item_decoration, null)
                recyclerView.setTag(R.id.empty_item_observer, null)
            }
        }
    }

    /**
     * Register a new observer to listen for data changes.
     *
     *
     * The adapter may publish a variety of events describing specific changes.
     * Not all adapters may support all change types and some may fall back to a generic
     * [ &quot;something changed&quot;][androidx.recyclerview.widget.RecyclerView.AdapterDataObserver.onChanged] event if more specific data is not available.
     *
     *
     * Components registering observers with an adapter are responsible for
     * [ unregistering][.unregisterAdapterDataObserver] those observers when finished.
     *
     * @param observer Observer to register
     *
     * @see .unregisterAdapterDataObserver
     */
    fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver)

    /**
     * Unregister an observer currently listening for data changes.
     *
     *
     * The unregistered observer will no longer receive events about changes
     * to the adapter.
     *
     * @param observer Observer to unregister
     *
     * @see .registerAdapterDataObserver
     */
    fun unregisterAdapterDataObserver(observer: RecyclerView.AdapterDataObserver)


    /**
     * Returns the total number of items in the data set held by the adapter.
     *
     * @return The total number of items in this adapter.
     */
    fun getItemCount(): Int

    /**
     * 添加或者移除空白布局
     */
    fun addOrRemoveEmptyHeaderDecor(recyclerView: RecyclerView) {
        //是否添加过空白显示
        val showEmptyHeaderOnEmptyData = isShowEmptyHeaderOnEmptyData()
        if (showEmptyHeaderOnEmptyData) {
            val emptyHeaderDecor = recyclerView.getTag(R.id.empty_item_decoration) as? EmptyHeaderDecoration
                    ?: return
            recyclerView.postDelayed({
                synchronized(recyclerView) {
                    val hasEmptyDecor = recyclerView.getTag(R.id.empty_has_item_decoration) as? Boolean ?: false
                    if (getItemCount() == 0) {
                        //空数据 没有添加的话 添加
                        if (!hasEmptyDecor) {
                            setEmptyDecor(recyclerView, true)
                            recyclerView.addItemDecoration(emptyHeaderDecor)
                        }
                    } else {
                        //有数据 没有移除的话 移除
                        if (hasEmptyDecor) {
                            setEmptyDecor(recyclerView, false)
                            recyclerView.removeItemDecoration(emptyHeaderDecor)
                        }
                    }
                }
            }, 100)
        }
    }


    /**
     * 没有数据的时候是否显示空白ItemDecoration
     */
    private fun isShowEmptyHeaderOnEmptyData(): Boolean = getEmptyText().isNotEmpty() || getEmptyImage() != 0

    /**
     * 空白提示信息
     */
    fun getEmptyText(): String = ""

    /**
     * 空白提示图片
     */
    fun getEmptyImage(): Int = 0

    /**
     * 设置是否显示了空白
     */
    private fun setEmptyDecor(recyclerView: RecyclerView, has: Boolean) = recyclerView.setTag(R.id.empty_has_item_decoration, has)


    /**
     * Empty Decoration
     */
    private class EmptyHeaderDecoration(recyclerView: RecyclerView, val emptyDecor: IEmptyItemDecoration) : RecyclerView.ItemDecoration() {

        var dy = 0
        var mPaint: Paint? = null
        var mBitmap: Bitmap? = null

        init {
            val emptyImage: Int = emptyDecor.getEmptyImage()
            if (emptyImage != 0) {
                mBitmap = BitmapFactory.decodeResource(recyclerView.resources, emptyImage)
            }
        }

        override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            val bitmap = mBitmap
            val resources = parent.resources
            val paint = mPaint ?: Paint(Paint.ANTI_ALIAS_FLAG).also {
                it.color = -0x666667
                it.textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15f, resources.displayMetrics)
                mPaint = it
            }
            val width = parent.width
            val height = parent.height
            val prefixText = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40f, resources.displayMetrics)
            val text: String = emptyDecor.getEmptyText()
            val textRect = Rect()
            paint.getTextBounds(text, 0, text.length, textRect)
            val textHeight = if (text.isEmpty()) 0 else textRect.height()
            if (bitmap != null) {
                val totalHeight = bitmap.height + textHeight + prefixText //图片加文字总高度
                val bX = width / 2 - bitmap.width / 2
                val bY = height / 2 - totalHeight / 2
                val tX = width / 2 - paint.measureText(text) / 2
                val tY = bY + bitmap.height + prefixText
                c.drawBitmap(bitmap, bX.toFloat(), bY + dy / 2.toFloat(), paint)
                c.drawText(text, tX, tY + dy / 2.toFloat(), paint)
            } else {
                c.drawText(text, ((width - textRect.width()) / 2).toFloat(), ((height - textHeight) / 2).toFloat(), paint)
            }
        }

        override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
            if (emptyDecor.isShowEmptyHeaderOnEmptyData()) {
                outRect[0, 0, 0] = view.height
            } else if (parent.getChildAdapterPosition(view) != emptyDecor.getItemCount()) {
                dy = view.height
                if (dy == 0) {
                    view.measure(0, 0)
                    dy = view.measuredHeight
                }
            }
        }
    }
}